<?php

namespace doc\analysis;

use yii;

class Orm
{
    /**
     * @var ReflectionDoc
     */
    public $phpdoc;

    function __construct()
    {
        $this->phpdoc = new ReflectionDoc();
    }

    function deldir($dir)
    {
        //删除目录下的文件：
        $dh = opendir($dir);

        while ($file = readdir($dh)) {
            if ($file != "." && $file != "..") {
                $fullpath = $dir . "/" . $file;
                //chmod($dir . "/" . $file,777);
                if (!is_dir($fullpath)) {
                    unlink($fullpath);
                } else {
                    $this->deldir($fullpath);
                }
            }
        }
    }

    public function DBtoPHP()
    {
        $dir = __DIR__ . "/../../ai/db/table/tables.php";

        if (!file_exists($dir)) {
            return OrmDBtoPHP::cteateTablesClass();
        }
        require_once ($dir);
        $namespace = 'ai\db\table\Tables';
        $reflection = new \ReflectionClass ($namespace);
        $pro = $reflection->getProperties();

        $str = [];
        foreach ($pro as $v) {
            $str[] = $v->name;
        }
        ksort($str);
        $strPro = implode('-', $str);

        $db = Yii::$app->db;
        $tables = $db->createCommand("show tables")->queryAll();

        $tab = [];
        foreach ($tables as $item){
            foreach ($item as $value){
                $tab[] = $value;
            }
        }
        ksort($tab);
        $strTab = implode('-', $tab);

        if (md5($strPro) !== md5($strTab)) {
            $this->deldir($dir);
            return OrmDBtoPHP::cteateTablesClass();
        }
    }
}

class OrmDBtoPHP
{
    static function cteateTablesClass()
    {
        $db = Yii::$app->db;

        $tables = $db->createCommand("show tables")->queryAll();

        $streams = '<?php
namespace ai\db\table;

require_once(__DIR__."/../base.php");
use ai\db\TablesBase;
class Tables
{
';

        foreach ($tables as $tb) {
            foreach ($tb as $t) {
                $streams .= "
    /**
    * @var TablesBase
    */
    public $" . $t . ";";

            }
        }

        $streams .= "

    function __construct()
    {
        ";
        foreach ($tables as $tb) {
            foreach ($tb as $t) {
                $streams .= "$" . 'this->' . $t . ' = new TablesBase("' . $t . '");
        ';
            }
        }
        $streams .= "
     }
}";

        $myfile = fopen(__DIR__ . "/../../ai/db/table/tables.php", "w") or die("Unable to open file!");
        fwrite($myfile, $streams);
        fclose($myfile);

        return true;
    }
}

use ReflectionClass;
use ReflectionMethod;

require_once (__DIR__.'/permissions.php');
class ReflectionDoc
{
    public $permission = null;

    private $sys = array();

    public function __construct()
    {
        $this->permission = new permissions();
    }

    private function _init()
    {
        $sysAlias = Yii::$app->params['sys'];

        foreach ($sysAlias as $k => $item) {
            $item['path'] = "";
            if (!empty($item['namespace']))
                $item['path'] = $item['dir'];

            $this->sys[] = $item;
        }

    }

    public function all()
    {
        $this->_init();
        $files = array();

        foreach ($this->sys as $sys) {
            $sys['items'] = $this->getFiles($sys['path'], $sys['namespace']);
            $files[] = $sys;
        }
        return $files;
    }

    public function one($appAlias, $sysInfo = [])
    {
        $this->_init();
        $files = array();
        foreach ($this->sys as $sys) {
            if ($sys["alias"] == $appAlias) {
                $files = $this->permission->reflection($sys['path'], $sys['namespace']);
            }
        }
        return $files;
    }

    public function cur()
    {
        list($sys, $dir, $file) = explode('\\', Yii::$app->controller->className());
        $this->app_name = $sys;
        $namespace = $sys . '\\interfaces\\' . str_replace('controller', 'interface', strtolower($file));
        $action = strtolower(Yii::$app->controller->action->actionMethod);


        $methods = $this->getClassMethods($namespace);

        $curMethod = false;
        foreach ($methods as $m) {
            if ($m['alias'] == $action)
                $curMethod = $m;
        }
        if (!$curMethod) {
            echo "未找到文档注释 ai->app->libs->orm";
            exit;
        }

        return new AnalysisDoc($sys, $curMethod);
    }

    private function getFiles($basedir, $sys)
    {
        $files = array();
        if (is_dir($basedir)) {
            if ($dh = opendir($basedir)) {
                while (($file = readdir($dh)) !== false) {
                    if ($file != '.' && $file != '..') {
                        if (!is_dir($basedir . "/" . $file)) {
                            $file = strtolower($file);
                            $fileName = rtrim($file, '.php');
                            $filePaht = $basedir . '\\' . $file;
                            $namespace = $sys . '\\interfaces\\' . $fileName;
                            $classDoc = $this->getClassDoc($namespace);

                            $f = array();
                            $f['controller'] = str_replace('interface', '', $fileName);
                            $f['namespace'] = strtolower($sys . '\\controllers\\' . str_replace('interface', 'controller', $fileName));//dealers\controllers\MainController
                            //$f['path'] = $filePaht;
                            $f['alias'] = $fileName;
                            $f['md5'] = md5_file($filePaht);
                            //$f['doc'] = $classDoc;
                            $f['name'] = $this->getStrByReg($classDoc, 'name');
                            $f['sort'] = $this->getStrByReg($classDoc, 'sort',0);
                            $f['remark'] = $this->getStrByReg($classDoc, 'remark');
                            $f['deprecated'] = $this->getStrBoolByReg($classDoc, 'deprecated');
                            $f['methods'] = $this->getClassMethods($namespace);
                            $files[] = $f;
                        }
                    }
                }
                closedir($dh);
            }
        }
        return $files;
    }

    private function getClassDoc($namespace)
    {
        $reflection = new ReflectionClass ($namespace);
        $doc = $reflection->getDocComment();
        return $doc;
    }

    private function getClassMethods($namespace)
    {
        $methodsArr = array();

        $reflection = new ReflectionClass ($namespace);
        $methods = $reflection->getMethods(ReflectionMethod::IS_PUBLIC);

        foreach ($methods as $method) {
            $doc = $method->getDocComment();

            $mArr = array();
            $mArr['name'] = $this->getStrByReg($doc, "name");
            $mArr['alias'] = strtolower($method->name);
            $mArr['action'] = str_replace('action', '', strtolower($method->name));
            //$mArr['doc'] = $doc;
            $mArr['remark'] = $this->getStrByReg($doc, "remark");//描述

            $pageType = $this->getStrByReg($doc, 'type');//页面类型
            $mArr['type'] = empty($pageType) ? "page" : $pageType;
            $mArr['guest'] = $this->getStrBoolByReg($doc, 'guest');//是否不登录也可以访问 游客访问

            $mArr['sort'] = $this->getStrByReg($doc, 'sort',0);

            $mArr['deprecated'] = $this->getStrBoolByReg($doc, 'deprecated');//是否弃用

            $common = $this->getStrBoolByReg($doc, 'common');//是否通用，不需要权限验证
            $strCommon = $this->getStrByReg($doc, 'common');
            $common = !$common ? 'no' : (empty($strCommon) ? 'all' : $strCommon);
            $mArr['common'] = $common;

            $mArr['get'] = $this->getStrsByReg($doc, 'get');
            $mArr['post'] = $this->getStrsByReg($doc, 'post');
            $mArr['getall']=$this->getStrBoolByReg($doc, 'getall');
            $mArr['postall']=$this->getStrBoolByReg($doc, 'postall');

            if ($common == 'get' && count($mArr['post']) > 1)
                $mArr['postall'] = true;
            if ($common == 'post' && count($mArr['get']) > 1)
                $mArr['getall'] = true;
            if ($common == "no") {
                if (count($mArr['post']) > 1)
                    $mArr['postall'] = true;
                if (count($mArr['get']) > 1)
                    $mArr['getall'] = true;
            }


            $methodsArr[] = $mArr;
        }

        return $methodsArr;
    }


    private function getStrByReg($doc, $reg,$str='')
    {
        preg_match("/\@{$reg} .+/", $doc, $strArr);
        if (count($strArr) > 0) {
            $str = ltrim($strArr[0], "\@{$reg} ");
        }
        return $str;
    }

    private function getStrsByReg($doc, $reg)
    {
        $pArr = array();
        preg_match_all("/\@{$reg} .+/", $doc, $strArr);
        if (count($strArr) > 0) {
            foreach ($strArr[0] as $item) {
                $str = ltrim($item, "\@{$reg}");
                $str = trim($str);

                $pm = array('title' => '', "key" => "", "value" => "");
                $arr = explode(',', $str);
                foreach ($arr as $n) {
                    list($k, $v) = explode(':', $n);
                    if ($k == 't')
                        $pm['title'] = $v;
                    if ($k == 'k')
                        $pm['key'] = $v;
                    if ($k == 'v')
                        $pm['value'] = $v;
                }
                $pArr[] = $pm;
            }
        }
        return $pArr;
    }

    private function getStrBoolByReg($doc, $reg)
    {
        $bool = false;
        preg_match("/\@{$reg}/", $doc, $strArr);
        if (count($strArr) > 0) {
            $bool = true;
        }
        return $bool;
    }

}

class AnalysisDoc
{
    public $appname = '';
    public $guest = false;
    public $common = "no";

    function __construct($appName, $docArr)
    {
        $this->appname = $appName;
        $this->guest = $docArr['guest'];
        $this->common = strtolower($docArr['common']);
    }

    public function baseAuth($loginUrl)
    {
        exit;

        if ($this->guest)
            return true;

        if (\Ai::$app->web->user->isGuest()) {
            Yii::$app->response->redirect($loginUrl)->send();
            exit;
        }

        if ($this->common == 'get' && Yii::$app->request->method == 'GET')
            return true;

        if ($this->common == 'post' && Yii::$app->request->method == 'POST')
            return true;

        if ($this->common == "all")
            return true;

        $user = \Ai::$app->web->user->getIdentity();
        $isSuperManager = isset($user['is_sys_manager']) ? $user['is_sys_manager'] : '0';
        if ($isSuperManager == '1')
            return true;
        $route = strtolower(Yii::$app->controller->route);
        $roleID = isset($user['role_id']) ? $user['role_id'] : 0;


        $curAllPermissions = \Ai::$db->query->sys_auth->getCurPermissions($route, $roleID)->all();

        if (Yii::$app->request->method == "GET") {

            $flag = false;
            $routeKey = '';
            foreach ($curAllPermissions as $per) {
                if ($per['req_method'] == 'getall')
                    return true;
                if (!empty($per['req_key']) && $per['req_method'] == 'get') {
                    $routeKey = $per['req_key'];
                }
                if ($per['type'] === '0')
                    $flag = true;
            }

            if (!empty($routeKey)) {
                if (isset($_GET[$routeKey])) {
                    $flag = false;
                    $curKeyValue = $_GET[$routeKey];
                    foreach ($curAllPermissions as $per) {
                        if ($per['req_key'] == $routeKey && $per['req_value'] == $curKeyValue) {
                            $flag = true;
                        }
                    }
                }
            }
            return $flag;
        }

        if (Yii::$app->request->method == "POST") {

            $flag = false;
            $routeKey = '';
            foreach ($curAllPermissions as $per) {
                if ($per['req_method'] == 'postall')
                    return true;
                if (!empty($per['req_key']) && $per['req_method'] == 'post') {
                    $routeKey = $per['req_key'];
                }
                if ($per['type'] === '0')
                    $flag = true;
            }

            if (!empty($routeKey)) {
                if (isset($_GET[$routeKey])) {
                    $flag = false;
                    $curKeyValue = $_GET[$routeKey];
                    foreach ($curAllPermissions as $per) {
                        if ($per['req_key'] == $routeKey && $per['req_value'] == $curKeyValue) {
                            $flag = true;
                        }
                    }
                }
            }
            return $flag;
        }

        return false;
    }
}


